﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using MediaPortal.Dialogs;
using MediaPortal.GUI.Library;
using dlCentral.GUI.Items;
using dlCentral.Localizations;
using dlCentral.PluginHandlers;
using dlCentral.Settings.Data;
using dlCentral.Utils;
using dlCentral.TorrentHandlers;
using dlCentral.Scrapper;
using NLog;

namespace dlCentral.GUI {
    public class Retriever {

        public static Retriever Instance {
            get {
                if (_instance == null)
                    _instance = new Retriever();

                return _instance;
            }
        }
        private static Retriever _instance = null;

        private dlCentralCore core = dlCentralCore.Instance;
        #region Private Variables
        private static Logger logger = LogManager.GetCurrentClassLogger();
        private bool _progressReportingEnabled = true;
        private Thread _downloaderThread = null;
        private bool _isCanceled = false;
        #endregion

        #region Delegates
        private delegate bool IsCanceledDelegate();
        private delegate void OnCompletedDelegate();
        private delegate bool OnQueryStartingDelegate();
        private delegate void OnProgressDelegate(string line1, string line2, string line3, int percent);
        #endregion

        #region Public Events
        public delegate void OnSiteSearchErrorDelegate(Exception e);
        public delegate void OnSiteSearchCompletedDelegate(List<MediaDetail> MediaDetails, bool canceled);
        public delegate void OnDownloadDelegate(MediaDetail mediaDetail, List<DownloadStatus> statusList);

        public event OnSiteSearchErrorDelegate OnSiteSearchErrorEvent;
        public event OnSiteSearchCompletedDelegate OnSiteSearchCompletedEvent;
        public event OnDownloadDelegate OnDownloadEvent;
        #endregion

        #region Public Constants
        #endregion

        #region Constructors
        private Retriever() {
        }
        #endregion

        #region Public Methods

        public bool IsStatusFileValidandPresent()
        {
            string CommPath = FileUtils.ensureBackSlash(Settings.SettingsManager.Properties.GeneralSettings.CommPath);
            if (File.Exists(CommPath + "status.txt"))
            {
                FileInfo fInfo = new FileInfo(CommPath + "status.txt");
                if (fInfo.Length>0) return true;
            }
            return false;
        }


        public void SearchForDownloads(MediaDetail mediaDetail) {
            if (IsCanceled())
                Kill();
            if (_downloaderThread != null && _downloaderThread.IsAlive)
                return;

            _isCanceled = false;
            _downloaderThread = new Thread(SearchSiteAsynch);
            _downloaderThread.IsBackground = true;
            _downloaderThread.Name = "Downloader Thread";
            _downloaderThread.Start(mediaDetail);
        }

        public bool IsCanceled() {
            if (!_progressReportingEnabled) return false;

            if (GUIGraphicsContext.form.InvokeRequired) {
                IsCanceledDelegate d = IsCanceled;
                return (bool)GUIGraphicsContext.form.Invoke(d);
            }

            GUIDialogProgress pDlgProgress = (GUIDialogProgress)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_PROGRESS);

            _isCanceled = pDlgProgress.IsCanceled;

            return (_isCanceled);
        }

        public bool IsRunning() {
            if (_downloaderThread != null && _downloaderThread.IsAlive) {
                return true;
            }
            return false;
        }

        public void Kill() {
            if (_downloaderThread != null && _downloaderThread.IsAlive) {
                _downloaderThread.Abort();
                _downloaderThread = null;
            }
        }
        #endregion

        #region Private Methods
        private void SearchSiteAsynch(object mediaDetailObj)
        {
            if (!(mediaDetailObj is MediaDetail))
                throw new ArgumentException("Parameter must be type of MediaDetail!");

            try {
                OnQueryStarting();
                List<MediaDetail> allResults = null;
                MediaDetail mediaDetail = (MediaDetail)mediaDetailObj;
                allResults = QuerySite(mediaDetail);
                if (OnSiteSearchCompletedEvent != null) {
                    OnSiteSearchCompletedEvent(allResults, _isCanceled);
                }

                OnCompleted();
            }
            catch (ThreadAbortException) {
                _isCanceled = true;
            }
            catch (Exception e) {
                try {
                    OnCompleted();
                }
                catch {
                }
                if (OnSiteSearchErrorEvent != null) {
                    OnSiteSearchErrorEvent(e);
                }
            }
        }

        private bool OnQueryStarting() {
            if (GUIGraphicsContext.form.InvokeRequired) {
                OnQueryStartingDelegate d = OnQueryStarting;
                return (bool)GUIGraphicsContext.form.Invoke(d);
            }

            GUIDialogProgress pDlgProgress = (GUIDialogProgress)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_PROGRESS);

            pDlgProgress.Reset();

            pDlgProgress.ShowProgressBar(true);

            pDlgProgress.SetHeading(Localization.SearchingSite);
            pDlgProgress.SetLine(1, Localization.Initializing);
            pDlgProgress.SetLine(2, string.Empty);

            pDlgProgress.SetPercentage(0);

            pDlgProgress.StartModal(GUIWindowManager.ActiveWindow);
            return true;
        }


        private List<MediaDetail> QuerySite(MediaDetail mediaDetail)
        {
            List<MediaDetail> allResults = new List<MediaDetail>();
            List<string> Query = new List<string>();
            List<string> RemoteDirs = new List<string>();
            string CommPath = FileUtils.ensureBackSlash(Settings.SettingsManager.Properties.GeneralSettings.CommPath);
            int TimeOut = Convert.ToInt32(Settings.SettingsManager.Properties.GeneralSettings.CommTimeOut);
            string Title = "";
            string LocalDir = "";
            SiteSearchType DownloadsSearchType = mediaDetail.SearchType;
            TorrentHandler CurrentHandler = null;
            switch (mediaDetail.Site.Host)
            {
                case "www.isohunt.com" :
                    CurrentHandler = core.TorrentHandlers[TorrentId.ISOHUNT];
                    break;
                case "www.kickasstorrents.com":
                    CurrentHandler = core.TorrentHandlers[TorrentId.KT];
                    break;
                case "cinematorrents.com":
                    CurrentHandler = core.TorrentHandlers[TorrentId.CT];
                    break;
                case "www.monova.org":
                    CurrentHandler = core.TorrentHandlers[TorrentId.MONOVA];
                    break;
                case "www.AliveTorrents.com":
                    CurrentHandler = core.TorrentHandlers[TorrentId.AT];
                    break;

            }

            switch (DownloadsSearchType)
            {
                case SiteSearchType.IMDb:
                    RemoteDirs = mediaDetail.Site.MovieRemoteDirs;
                    LocalDir = FileUtils.ensureBackSlash(mediaDetail.Site.MovieLocalDir);
                    Title = mediaDetail.Site.SearchTerm;
                    break;

                case SiteSearchType.TVSHOW:

                    RemoteDirs = mediaDetail.Site.TVRemoteDirs;
                    LocalDir = FileUtils.ensureBackSlash(mediaDetail.Site.TVLocalDir);
                    if (mediaDetail.Site.SiteType != "Torrent")
                    {
                        Title = dlCentralUtils.GetModifiedTVSeries(mediaDetail.Title);
                    }
                    else Title = mediaDetail.Title + " ";

                    Title = Title + dlCentralUtils.GetSeparatorTVSeries(mediaDetail.Title);
                    Title = Title + dlCentralUtils.GetSeasonFormatTVSeries(mediaDetail.Title) + mediaDetail.SeasonStr;
                    Title = Title + dlCentralUtils.GetEpisodeFormatTVSeries(mediaDetail.Title) + mediaDetail.EpisodeStr;
                    break;
                case SiteSearchType.MOVIE:
                    break;
                case SiteSearchType.NONE:
                    break;
            }

            if (CurrentHandler != null)
            {
                CurrentHandler.Site = mediaDetail.Site;
                CurrentHandler.DLSType = mediaDetail.SearchType;
                CurrentHandler.SearchTerm = Title;
                CurrentHandler.GetDetails(allResults);
            }
            else
            foreach (string str in RemoteDirs)
            {
                Random random = new Random();

                int num = random.Next(0xFFFFFF);

                
                System.IO.StreamWriter lfile = new System.IO.StreamWriter(CommPath + string.Format("lock_{0}.dat",num));
                lfile.Close();
                Query.Clear();
                Query.Add(mediaDetail.Site.Host);
                Query.Add(mediaDetail.Site.Port);
                Query.Add(mediaDetail.Site.Protocol);
                if (mediaDetail.Site.PASV) Query.Add("1"); else Query.Add("0");
                Query.Add(mediaDetail.Site.UserName);
                Query.Add(mediaDetail.Site.Password);
                Query.Add(str);
                Query.Add(LocalDir);
                Query.Add(Title);
                System.IO.StreamWriter file = new System.IO.StreamWriter(CommPath + mediaDetail.Site.SiteType + string.Format("GetList_{0}.qwr", num));
                foreach (string str1 in Query) file.WriteLine(str1);
                file.Close();
                int i = 0;
                while (File.Exists(CommPath + string.Format("lock_{0}.dat",num)))
                {
                    Thread.Sleep(1000);
                    i++;
                    OnProgress(string.Format("Waiting for Respons from {0}", mediaDetail.Site.SiteName), "", "", (i*100/TimeOut));
                    if (i > TimeOut)
                    {
                        File.Delete(CommPath + string.Format("lock_{0}.dat",num));
                        File.Delete(CommPath + string.Format("GetList_{0}.qwr", num));
                        OnCompleted();
                        throw new LoginFailedException(mediaDetail.Site.SiteName);
                    }
                    if (File.Exists(CommPath + string.Format("error_{0}.txt",num)))
                    {
                        File.Delete(CommPath + string.Format("error_{0}.txt",num));
                        OnCompleted();
                        throw new LoginFailedException(mediaDetail.Site.SiteName);
                    }
                }
                if (File.Exists(CommPath + string.Format("result_{0}.txt",num)))
                {
                    List<string> res = new List<string>();
                    res.AddRange(File.ReadAllLines(CommPath + string.Format("result_{0}.txt",num)));
                    foreach (string str1 in res)
                    {
                        MediaDetail dl = new MediaDetail();
                        string[] s1 = str1.Split('|');
                        dl.Name = s1[0];
                        DateTime MyDateTime;
                        MyDateTime = new DateTime();
                        MyDateTime = DateTime.Parse(s1[1]);
                        dl.Date = MyDateTime;
                        dl.RemoteDir = str;
                        dl.SearchType = DownloadsSearchType;
                        dl.Site = mediaDetail.Site;
                        allResults.Add(dl);
                    }
                   File.Delete(CommPath + string.Format("result_{0}.txt",num));
                }
                else { }
 
            }
            
            return allResults;
        }

            private void OnProgress(string line1, string line2, string line3, int percent) {
            if (!_progressReportingEnabled) return;

            if (GUIGraphicsContext.form.InvokeRequired) {
                OnProgressDelegate d = OnProgress;
                GUIGraphicsContext.form.Invoke(d, line1, line2, line3, percent);
                return;
            }

            GUIDialogProgress pDlgProgress = (GUIDialogProgress)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_PROGRESS);

            if (percent > 0)
                pDlgProgress.SetPercentage(percent); 
            pDlgProgress.ShowProgressBar(true);
            pDlgProgress.SetLine(1, line1);
            pDlgProgress.SetLine(2, line2);
            pDlgProgress.SetLine(3, line3);

 
           
            pDlgProgress.Progress();
         }

        private void OnCompleted() {
            if (!_progressReportingEnabled) return;

            if (GUIGraphicsContext.form.InvokeRequired) {
                OnCompletedDelegate d = OnCompleted;
                GUIGraphicsContext.form.Invoke(d);
                return;
            }

            GUIDialogProgress pDlgProgress = (GUIDialogProgress)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_PROGRESS);

            if (pDlgProgress != null)
                pDlgProgress.Close();
        }
        #endregion

        #region Download
        public void Download(MediaDetail downloadItem) {

//            DownloadDownloader.Core.IDownloadDownloader subDownloader = DownloadItem.Downloader; ;
            string LocalDir = "";
            string CommPath = FileUtils.ensureBackSlash(Settings.SettingsManager.Properties.GeneralSettings.CommPath);
            List<string> Query = new List<string>();
            string Download = downloadItem.Name;
            switch (downloadItem.SearchType)
            {
                case SiteSearchType.IMDb:
                    LocalDir = FileUtils.ensureBackSlash(downloadItem.Site.MovieLocalDir);
                    break;
                case SiteSearchType.TVSHOW:
                    LocalDir = FileUtils.ensureBackSlash(downloadItem.Site.TVLocalDir);
                    break;
            }
            Random random = new Random();
            int num = random.Next(0xFFFFFF);
            logger.Info("download remotedir {0}", downloadItem.RemoteDir);
            logger.Info("download localdir  {0}", LocalDir);
            Query.Clear();
            Query.Add(downloadItem.Site.Host);
            Query.Add(downloadItem.Site.Port);
            Query.Add(downloadItem.Site.Protocol);
            if (downloadItem.Site.PASV) Query.Add("1"); else Query.Add("0");
            Query.Add(downloadItem.Site.UserName);
            Query.Add(downloadItem.Site.Password);
            Query.Add(downloadItem.RemoteDir + downloadItem.Name);
            Query.Add(LocalDir + downloadItem.Name);
            Query.Add(downloadItem.TorrentURL);  
            System.IO.StreamWriter file = new System.IO.StreamWriter(CommPath + downloadItem.Site.SiteType + string.Format("GetDL_{0}.qwr",num));
            foreach (string str1 in Query) file.WriteLine(str1);
            file.Close();

//            while (File.Exists(LocalDir + "GetDL.qwr")) Thread.Sleep(1000);
//            while (!File.Exists(LocalDir + "processed.txt")) Thread.Sleep(1000);
//            File.Delete(LocalDir + "processed.txt");

            DownloadStatus newDownloadStatus = new DownloadStatus();
            List<DownloadStatus> statusList = new List<DownloadStatus>();

            newDownloadStatus.Status = DownloadStatusStatus.Succesful;
            statusList.Add(newDownloadStatus);
            if (OnDownloadEvent != null)
                OnDownloadEvent(downloadItem, statusList);
        }
        #endregion

        private class CustomDownloadDownloader {
     //       public DownloadDownloader.Core.IDownloadDownloader downloader { get; set; }
            public string downloaderTitle { get; set; }
        }
    }
}